<?php
/**
 * 业务逻辑用异常，错误代码需要查手册才知道意义，为与其它接口交换数据时快速识别错误类型
 * 添加关键字key，以避免在其它交互业务中直接用code造成代码不易理解
 * @author 张军磊  zhangjunlei26@gmail.com
 */
if (! defined('ENVIRON')) define('ENVIRON', 'development'); // development,testing,production
class Error extends Exception
{

	/**
	 *
	 * @var string 语言包名
	 */
	protected $package;

	/**
	 *
	 * @var string 语言key名
	 */
	protected $key;

	/**
	 *
	 * @var string 语言包名+语言key名
	 */
	protected $_key;

	/**
	 *
	 * @var string 错误时渲染模板
	 */
	public static $error_view = 'error/error';

	/**
	 *
	 * @var string error view content type
	 */
	public static $error_view_content_type = 'text/html';

	/**
	 * 已经记录错误了
	 *
	 * @var boolean
	 */
	protected $has_loged = FALSE;

	public function __construct ($package ,$key ,$values = array() ,$lang = 'en-us' ,$code = 0 ,$previous = NULL)
	{
		$this->package = $package;
		$this->key = $key;
		$this->_key = "{$package}.{$key}";
		parent::__construct(__($package, $key, $values, $lang), $code, $previous);
	}

	/**
	 * 判断是否为某一类型错误
	 *
	 * @param $key string       	
	 */
	public function is ($key)
	{
		return $this->_key === $key;
	}

	/**
	 * 取属性
	 */
	public function __get ($key)
	{
		return isset($this->$key) ? $this->$key : NULL;
	}

	public function __toString ()
	{
		$trace = $this->getTrace();
		$t = array();
		foreach ($trace as $k => $v)
		{
			$class = isset($v['class']) ? $v['class'] : '';
			$type = isset($v['type']) ? $v['type'] : '';
			$file = isset($v['file']) ? $v['file'] : '[internal function]';
			$line = isset($v['line']) ? "({$v['line']})" : '';
			$func = $v['function'];
			$args = array();
			foreach ($v['args'] as $k2 => $val)
			{
				if (is_scalar($val))
				{
					$args[] = (is_int($val) || is_float($val)) ? $val : "'{$val}'";
				}
				else
				{
					if ($val)
					{
						$args[] = var_export($val, TRUE);
					}
					else
					{
						$args[] = (is_array($val)) ? 'array()' : $val;
					}
				}
			}
			$args = implode(',', $args);
			$t[] = "#{$k} {$file}{$line}: {$class}{$type}{$func}($args)";
		}
		++ $k;
		$t[] = "#{$k} {main}";
		$trace = implode("\n", $t);
		$msg = "exception '" . __CLASS__ . "' with message '" . $this->getMessage() . "' in " . $this->getFile() . ":" . $this->getLine();
		$code = $this->getCode();
		$file = $this->getFile();
		$line = $this->getLine();
		$key = $this->_key;
		$msg = "{$msg}\n#code {$code}\n#key {$key}\n{$trace}";
		return $msg;
	}

	public static function throw_on ($flag ,$package ,$key ,$values = array() ,$lang = 'en-us' ,$code = 0)
	{
		$class = __CLASS__;
		if ($flag) throw new $class($package, $key, $values, $lang, $code);
	}

	public function log ($group = NULL)
	{
		$this->has_loged = 1;
		return self::log_exception($this, $group ? $group : $this->package);
	}


	/**
	 * 日志异常
	 *
	 * @param $e Exception       	
	 * @param $group string       	
	 */
	public static function log_exception (Exception $e ,$group = 'default')
	{
		return Logger::error($e, $group);
	}

	/**
	 * 进行日志
	 */
	public function __destruct ()
	{
		if (! $this->has_loged) $this->log();
	}
}